﻿#region

using System.Collections.Generic;
using Diagnostics.Annotations;
using MobilePal.Collections;
using MobilePal.Log;
using MobilePal.Rules;
using MobilePal.State;
using System.Linq;

#endregion

namespace MobilePal.ProcessorAgents
{
    public sealed class RulesAgent : IProcessorAgent
    {
        private readonly List<RuleAgent> _ruleMonitors = new List<RuleAgent>();
        private List<ILogger> _loggers;
        private ApplicationState _state;

        public void AttachToState(List<ILogger> loggers, [NotNull] ApplicationState applicationState)
        {
            _loggers = loggers;
            _state = applicationState;

            BuildRuleAgents(applicationState.Rules);

            applicationState.Rules.CollectionChanged += RuleCollectionChanged;
        }

        private void BuildRuleAgents(IEnumerable<ActivityRule> rules)
        {
            _ruleMonitors.Clear();

            foreach (var activityRule in rules)
            {
                var ruleAgent = new RuleAgent();
                ruleAgent.AttachToState(_loggers, _state);
                ruleAgent.ActivityRule = activityRule;
                _ruleMonitors.Add(ruleAgent);
            }
        }

        public void DetachFromState([NotNull] ApplicationState applicationState)
        {
            applicationState.Rules.CollectionChanged -= RuleCollectionChanged;
        }

        #region Methods
        private void RuleCollectionChanged(object sender, NotifyCollectionChangedEventArgs<ActivityRule> e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    OnRulesAdded(e.NewItems);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    OnRulesRemoved(e.OldItems);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    OnRulesRemoved(e.OldItems);
                    OnRulesAdded(e.NewItems);
                    break;
            }
        }

        private void OnRulesAdded(IEnumerable<ActivityRule> newItems)
        {
            foreach (var newItem in newItems)
            {
                ActivityRule activityRule = newItem;
                RuleAgent ruleAgent =
                    _ruleMonitors.FirstOrDefault(rule => rule.ActivityRule == activityRule);

                if (ruleAgent == null)
                {
                    ruleAgent = new RuleAgent();
                    ruleAgent.AttachToState(_loggers, _state);

                    ruleAgent.ActivityRule = activityRule;

                    _ruleMonitors.Add(ruleAgent);
                }
            }
        }

        private void OnRulesRemoved(IEnumerable<ActivityRule> oldItems)
        {
            foreach (var oldItem in oldItems)
            {
                ActivityRule activityRule = oldItem;
                RuleAgent ruleAgent =
                    _ruleMonitors.FirstOrDefault(rule => rule.ActivityRule == activityRule);

                if (ruleAgent != null)
                {
                    ruleAgent.DetachFromState(_state);
                    _ruleMonitors.Remove(ruleAgent);
                }
            }                
        }

        #endregion

    }
}